/*
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *
 *   版权所有  2014-2015 成都星锐蓝海网络科技有限公司
 *   商业许可请联系  +86-18682011860    QQ:66442834
 *   
 */



#include <stdio.h>
#include <limits.h>
#include <string.h>
#include <stdarg.h>
#include "xyz_str.h"

xyz_str_t *xyz_str_malloc(xyz_sli_t size)
{
	if (size < 0) { return NULL; }
	xyz_str_t *s = (xyz_str_t *)calloc(1, (sizeof(xyz_str_t) + size + 1));
	if (s) {
		s->len = size;
		if (size > 0) { s->data = (xyz_u8_t *)(((xyz_u8_t *)s) + sizeof(xyz_str_t)); }
	}
	return s;
}

xyz_str_t *xyz_str_malloc_text(const char *text, xyz_sli_t size)
{
	if (size < 0) { return NULL; }
	xyz_str_t *s = (xyz_str_t *)calloc(1, (sizeof(xyz_str_t) + size + 1));
	if (s) {
		s->len = size;
		s->data = (xyz_u8_t *)(((xyz_u8_t *)s) + sizeof(xyz_str_t));
		if (text && size > 0) { memcpy(s->data, text, size); }
	}
	return s;
}

xyz_str_t *xyz_str_malloc_i32(xyz_i32_t n)
{
	char text[512] = { 0 };
	int size = 0;
	size = snprintf(text, sizeof(text) - 1, "%ld", n);
	if (size < 1) {
		return NULL;
	}
	xyz_str_t *s = (xyz_str_t *) calloc(1, (sizeof(xyz_str_t) + size + 1));
	if (s) {
		s->len = size;
		s->data = (xyz_u8_t *) (((xyz_u8_t *) s) + sizeof(xyz_str_t));
		memcpy(s->data, text, size);
	}
	return s;
}

xyz_str_t *xyz_str_malloc_u32(xyz_u32_t n)
{
	char text[512] = { 0 };
	int size = 0;
	size = snprintf(text, sizeof(text) - 1, "%ld", n);
	if (size < 1) {
		return NULL;
	}
	xyz_str_t *s = (xyz_str_t *) calloc(1, (sizeof(xyz_str_t) + size + 1));
	if (s) {
		s->len = size;
		s->data = (xyz_u8_t *) (((xyz_u8_t *) s) + sizeof(xyz_str_t));
		memcpy(s->data, text, size);
	}
	return s;
}

xyz_str_t *xyz_str_malloc_i64(xyz_i64_t n)
{
	char text[512] = { 0 };
	int size = 0;
	size = snprintf(text, sizeof(text) - 1, "%lld", n);
	if (size < 1) {
		return NULL;
	}
	xyz_str_t *s = (xyz_str_t *) calloc(1, (sizeof(xyz_str_t) + size + 1));
	if (s) {
		s->len = size;
		s->data = (xyz_u8_t *) (((xyz_u8_t *) s) + sizeof(xyz_str_t));
		memcpy(s->data, text, size);
	}
	return s;
}

xyz_str_t *xyz_str_malloc_u64(xyz_u64_t n)
{
	char text[512] = { 0 };
	int size = 0;
	size = snprintf(text, sizeof(text) - 1, "%lld", n);
	if (size < 1) {
		return NULL;
	}
	xyz_str_t *s = (xyz_str_t *) calloc(1, (sizeof(xyz_str_t) + size + 1));
	if (s) {
		s->len = size;
		s->data = (xyz_u8_t *) (((xyz_u8_t *) s) + sizeof(xyz_str_t));
		memcpy(s->data, text, size);
	}
	return s;
}

void xyz_str_lower(xyz_u8_t *s, xyz_sli_t len)
{
    while (len > 0) {
        *s = tolower(*s);
        s++;
        len--;
    }
}

void xyz_str_upper(xyz_u8_t *s, xyz_sli_t len)
{
    while (len > 0) {
        *s = toupper(*s);
        s++;
        len--;
    }
}


//  跳过空白字符'\f' '\n' '\r' '\t' '\v'
xyz_sli_t xyz_str_skip_spaces(const xyz_u8_t *s, xyz_sli_t len)
{
	xyz_sli_t i;
	if (!s || len < 1) { return -1; }
	for (i = 0; (i < len) && (isspace(s[i])); i++);
	return ((i == len) ? -1 : i);
}

//  获取数字开始位置
xyz_sli_t xyz_str_skip_to_digit(const xyz_u8_t *s, xyz_sli_t len)
{
	xyz_sli_t i;
	if (!s || len < 1) { return -1; }
	for (i = 0; (i < len) && !(isdigit(s[i])); i++);
	return ((i == len) ? -1 : i);
}

//  获取不是数字开始位置
xyz_sli_t xyz_str_skip_to_undigit(const xyz_u8_t *s, xyz_sli_t len)
{
	xyz_sli_t i;
	if (!s || len < 1) { return -1; }
	for (i = 0; (i < len) && (isdigit(s[i])); i++);
	return ((i == len) ? -1 : i);
}

//  获取十六进制数字开始位置
xyz_sli_t xyz_str_skip_to_hex(const xyz_u8_t *s, xyz_sli_t len)
{
	xyz_sli_t i;
	if (!s || len < 1) { return -1; }
	for (i = 0; (i < len) && !(isxdigit(s[i])); i++);
	return ((i == len) ? -1 : i);
}

//  获取不是十六进制数字开始位置
xyz_sli_t xyz_str_skip_to_unhex(const xyz_u8_t *s, xyz_sli_t len)
{
	xyz_sli_t i;
	if (!s || len < 1) { return -1; }
	for (i = 0; (i < len) && (isxdigit(s[i])); i++);
	return ((i == len) ? -1 : i);
}

//  获取可显示字符开始位置
xyz_sli_t xyz_str_skip_to_graph(const xyz_u8_t *s, xyz_sli_t len)
{
	xyz_sli_t i;
	if (!s || len < 1) { return -1; }
	for (i = 0; (i < len) && !(isgraph(s[i])); i++);
	return ((i == len) ? -1 : i);
}

//  获取不可显示字符开始位置
xyz_sli_t xyz_str_skip_to_ungraph(const xyz_u8_t *s, xyz_sli_t len)
{
	xyz_sli_t i;
	if (!s || len < 1) { return -1; }
	for (i = 0; (i < len) && (isgraph(s[i])); i++);
	return ((i == len) ? -1 : i);
}

//  获取可打印字符开始位置
xyz_sli_t xyz_str_skip_to_print(const xyz_u8_t *s, xyz_sli_t len)
{
	xyz_sli_t i;
	if (!s || len < 1) { return -1; }
	for (i = 0; (i < len) && !(isprint(s[i])); i++);
	return ((i == len) ? -1 : i);
}

//  获取不可打印字符开始位置
xyz_sli_t xyz_str_skip_to_unprint(const xyz_u8_t *s, xyz_sli_t len)
{
	xyz_sli_t i;
	if (!s || len < 1) { return -1; }
	for (i = 0; (i < len) && (isprint(s[i])); i++);
	return ((i == len) ? -1 : i);
}

//  获取指定字符第一次出现的位置
xyz_sli_t xyz_str_chr(const xyz_u8_t *s, xyz_sli_t len, xyz_u8_t ch)
{
	xyz_sli_t i;
	if (!s || len < 1) { return -1; }
	for (i = 0; (i < len) && (s[i] != ch); i++);
	return ((i == len) ? -1 : i);
}

//  获取指定字符最后一次出现的位置
xyz_sli_t xyz_str_rchr(const xyz_u8_t *s, xyz_sli_t len, xyz_u8_t ch)
{
	xyz_sli_t i;
	if (!s || len < 1) { return -1; }
	for (i = len; (i > -1) && (s[i] != ch); --i);
	return i;
}

//  获取字符串s2在字符串s1中第一次开始的位置
xyz_sli_t xyz_str_str(const xyz_u8_t *s1, xyz_sli_t len1, const xyz_u8_t *s2, xyz_sli_t len2)
{
	xyz_sli_t i, j, k;
	if (!s1 || !s2 || len1 < 1 || len2 < 1) { return -1; }
	for (i = 0; i < len1;  ++i) {
		for (k = i, j = 0; (k < len1) && (j < len2) && (s1[k] == s2[j]); ++k, ++j);
	}
	return ((j != len2) ? -1 : ((s1[i-1] == s2[j-1]) ?  i : -1));
}

//  获取字符串s2在字符串s1中最后一次开始的位置
xyz_sli_t xyz_str_rstr(const xyz_u8_t *s1, xyz_sli_t len1, const xyz_u8_t *s2, xyz_sli_t len2)
{
	xyz_sli_t i, j, k;
	if (!s1 || !s2 || len1 < 1 || len2 < 1) { return -1; }
	for (i = len1; i > -1;  --i) {
		for (k = i, j = len2; (k > -1) && (j > -1) && (s1[k] == s2[j]); --k, --j);
	}
	return i;
}

//  忽略大消息比较两个字符串
int xyz_str_casecmp(const xyz_u8_t *s1, xyz_sli_t len1, const xyz_u8_t *s2, xyz_sli_t len2)
{
	xyz_sli_t i, n;
	if (!s1 || !s2 || len1 != len2 || len1 < 1) { return -1; }
	if (s1 == s2) { return 0; }
	for (i = 0, n = 0; (i < len1) && (0 == (n = (tolower(s1[i]) - tolower(s2[i])))); ++i);
	return (n ? -1 : 0);
}

//  忽略大消息比较两个字符串前n个字符
int xyz_str_ncasecmp(const xyz_u8_t *s1, xyz_sli_t len1, const xyz_u8_t *s2, xyz_sli_t len2, xyz_sli_t n)
{
	xyz_sli_t i, c;
	if (!s1 || !s2 || len1 < 1 || len2 < 1 || n < 1) { return -1; }
	if ((s1 == s2) && (len1 == len2)) { return 0; }
	if (((len1 != len2) && (len1 < n) && (len2 < n))
			|| ((len1 < n) && (len2 > n))
			|| ((len1 > n) && (len2 < n))) {
		return -1;
	}
	if ((len1 == len2) && (len1 <= n)) { n = len1; }
	for (i = 0, c = 0; (i < n) && (0 == (c = (tolower(s1[i]) - tolower(s2[i])))); ++i);
	return (c ? -1 : 0);
}



// 31 131 1313 13131 131313 etc..
xyz_uli_t xyz_str_BKDR_hash(const xyz_u8_t *in, xyz_sli_t len, xyz_uli_t seed, xyz_uli_t hash)
{
	xyz_uli_t rc = 0;
	xyz_sli_t i = 0;

	for ( ; i < len; i++) {
		rc = rc * seed + (*in++);
	}
	if (4 == sizeof(rc)) {
		return ((rc % hash) & 0x7FFFFFFF);
	}
	if (8 == sizeof(rc)) {
		return ((rc % hash) & 0x7FFFFFFFFFFFFFFF);
	}
	return (rc % hash);
}
